﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Marmat.Forms.Skin
{
    /// <summary>
    /// 表示节点的 System.Windows.Forms.TreeView。
    /// </summary>
    public class TreeNode
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal TreeNodeCollection nodes;

        /// <summary>
        /// 获取一个值，该值指示树节点是否处于展开状态。
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal bool isExpanded;
        /// <summary>
        /// 获取一个值，该值指示树节点是否处于选定状态。
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal bool isSelected;

        /// <summary>
        /// 获取一个值，该值指示树节点为可见或部分可见。
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal bool isVisible;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal Rectangle bounds;

        /// <summary>
        /// 节点所在的集合中。
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal TreeNodeCollection parentCollection;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private bool @checked;

        /// <summary>
        /// 初始化 System.Windows.Forms.TreeNode 类的新实例。
        /// </summary>
        public TreeNode()
        {
        }

        /// <summary>
        /// 新实例初始化 System.Windows.Forms.TreeNode 类，具有指定的标签文本。
        /// </summary>
        /// <param name="text">标签 System.Windows.Forms.TreeNode.Text 节点的树节点。</param>
        public TreeNode(string text)
        {
            this.Text = text;
        }

        /// <summary>
        /// 新实例初始化 System.Windows.Forms.TreeNode 用指定的标签文本和子树节点的类。
        /// </summary>
        /// <param name="text">标签 System.Windows.Forms.TreeNode.Text 节点的树节点。</param>
        /// <param name="children">子数组 System.Windows.Forms.TreeNode 对象。</param>
        public TreeNode(string text, TreeNode[] children)
        {
            this.Text = text;
            this.Nodes.AddRange(children);
        }

        /// <summary>
        /// 新实例初始化 System.Windows.Forms.TreeNode 用指定的标签文本以及当树节点处于选定和未选定状态时要显示的图像的类。
        /// </summary>
        /// <param name="text">标签 System.Windows.Forms.TreeNode.Text 节点的树节点。</param>
        /// <param name="imageIndex">索引值 System.Drawing.Image 若要取消选定的树节点时显示。</param>
        /// <param name="selectedImageIndex">索引值 System.Drawing.Image 选中树节点时显示。</param>
        public TreeNode(string text, int imageIndex, int selectedImageIndex)
        {
            this.Text = text;
            this.ImageIndex = imageIndex;
            this.SelectedImageIndex = selectedImageIndex;
        }

        /// <summary>
        /// 新实例初始化 System.Windows.Forms.TreeNode 用指定的标签文本、 子树节点，以及当树节点处于选定和未选定状态时要显示的图像的类。
        /// </summary>
        /// <param name="text">标签 System.Windows.Forms.TreeNode.Text 节点的树节点。</param>
        /// <param name="imageIndex">索引值 System.Drawing.Image 若要取消选定的树节点时显示。</param>
        /// <param name="selectedImageIndex">索引值 System.Drawing.Image 选中树节点时显示。</param>
        /// <param name="children">子数组 System.Windows.Forms.TreeNode 对象。</param>
        public TreeNode(string text, int imageIndex, int selectedImageIndex, TreeNode[] children)
        {
            this.Text = text;
            this.ImageIndex = imageIndex;
            this.SelectedImageIndex = selectedImageIndex;
        }

        /// <summary>
        /// 获取树节点的树节点集合中的位置。
        /// </summary>
        /// <returns>一个表示树节点中的位置的从零开始的索引值 System.Windows.Forms.TreeNode.Nodes 集合。</returns>
        [Category("行为")]
        [Description("树节点在树节点集合中的位置。")]
        public int Index
        {
            get
            {
                if (this.TreeView is null)
                    return -1;
                else
                    return this.parentCollection.IndexOf(this);
            }
        }

        /// <summary>
        /// 获取一个值，该值指示树节点是否处于展开状态。
        /// </summary>
        /// <returns>true 如果树节点处于展开状态，则否则为 false。</returns>
        [Browsable(false)]
        public bool IsExpanded => isExpanded;

        /// <summary>
        /// 获取一个值，该值指示树节点是否处于选定状态。
        /// </summary>
        /// <returns>true 如果树节点处于选定状态，则否则为 false。</returns>
        [Browsable(false)]
        public bool IsSelected => isSelected;
        /// <summary>
        /// 获取一个值，该值指示树节点为可见或部分可见。
        /// </summary>
        /// <returns>true 如果树节点是可见的还是部分可见，则否则为 false。</returns>
        [Browsable(false)]
        public bool IsVisible => isVisible;
        /// <summary>
        /// 获取最后一个子树节点。
        /// </summary>
        /// <returns>一个 System.Windows.Forms.TreeNode 表示最后一个子树节点。</returns>
        [Browsable(false)]
        public TreeNode LastNode { get; }

        /// <summary>
        /// 获取从零开始的树节点的深度 System.Windows.Forms.TreeView 控件。
        /// </summary>
        /// <returns>中的树节点的从零开始深度 System.Windows.Forms.TreeView 控件。</returns>
        [Browsable(false)]
        public int Level
        {
            get
            {
                if (this.TreeView is null)
                    return -1;
                int level = 0;
                TreeNode treeNode = this;
                do
                {
                    if (treeNode.Parent is not null)
                        level++;
                    treeNode = treeNode.Parent;
                } while (treeNode is not null);
                return level;
            }
        }

        /// <summary>
        /// 获取下一个同级树节点。
        /// </summary>
        /// <returns>一个 System.Windows.Forms.TreeNode 表示下一个同级树节点。</returns>
        [Browsable(false)]
        public TreeNode NextNode
        {
            get
            {
                if (this.parentCollection is null)
                    return null;
                bool exist = false;
                TreeNode result = null;
                foreach (TreeNode node in this.parentCollection)
                {
                    if (exist)
                    {
                        result = node;
                        break;
                    }
                    if (node == this)
                        exist = true;
                }
                return result;
            }
        }

        ///// <summary>
        ///// 获取下一个可见的树节点。
        ///// </summary>
        ///// <returns>一个 System.Windows.Forms.TreeNode 表示下一个可见的树节点。</returns>
        //[Browsable(false)]
        //public TreeNode NextVisibleNode { get; }

        /// <summary>
        /// 获取或设置用于在树节点标签上显示文本的字体。
        /// </summary>
        /// <returns>System.Drawing.Font 用于在树节点标签上显示文本。</returns>
        [DefaultValue(null)]
        [Localizable(true)]
        [Category("外观")]
        [Description("树节点的前景色。")]
        public Font NodeFont { get; set; }

        /// <summary>
        /// 获取上一个同级树节点。
        /// </summary>
        /// <returns>一个 System.Windows.Forms.TreeNode 代表上一个同级树节点。</returns>
        [Browsable(false)]
        public TreeNode PrevNode
        {
            get
            {
                if (this.parentCollection is null)
                    return null;
                TreeNode prevNode = null;
                TreeNode result = null;
                foreach (TreeNode node in this.parentCollection)
                {
                    if (node == this)
                        result = prevNode;
                    prevNode = node;
                }
                return result;
            }
        }

        /// <summary>
        /// 获取当前的树节点的树节点的父级。
        /// </summary>
        /// <returns>一个 System.Windows.Forms.TreeNode ，表示当前的树节点的父节点。</returns>
        [Browsable(false)]
        public TreeNode Parent
        {
            get => this.parentCollection?.parent;
        }

        /// <summary>
        /// 获取或设置当节点处于选定状态时，与此树节点关联的图像的键。
        /// </summary>
        /// <returns>当节点处于选定状态时，与此树节点关联的图像的键。</returns>
        [DefaultValue("")]
        [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [RelatedImageList("TreeView.ImageList")]
        [Category("行为")]
        [Description("标识当节点未被选中时在该节点上显示的图像。")]
        [TypeConverter(typeof(TreeViewImageKeyConverter))]
        public string ImageKey { get; set; }

        ///// <summary>
        ///// 获取上一个可见的树节点。
        ///// </summary>
        ///// <returns>一个 System.Windows.Forms.TreeNode 代表上一个可见的树节点。</returns>
        //[Browsable(false)]
        //public TreeNode PrevVisibleNode { get; }

        /// <summary>
        /// 获取或设置当树节点处于选定状态时显示的图像的图像列表索引值。
        /// </summary>
        /// <returns>一个表示中的图像位置的从零开始的索引值 System.Windows.Forms.ImageList。</returns>
        [DefaultValue(-1)]
        [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [RelatedImageList("TreeView.ImageList")]
        [Category("行为")]
        [Description("图像列表值中的项，表示当树节点处于选中状态时要显示的图像。")]
        [TypeConverter(typeof(TreeViewImageIndexConverter))]
        public int SelectedImageIndex { get; set; }


        /// <summary>
        /// 获取或设置处于选定状态时，树节点中显示的图像的键。
        /// </summary>
        /// <returns>当树节点处于选定状态时显示的图像的键。</returns>
        [DefaultValue("")]
        [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [RelatedImageList("TreeView.ImageList")]
        [Category("行为")]
        [Description("ImageList值中的键，表示当树节点处于选定状态时要显示的图像。")]
        [TypeConverter(typeof(TreeViewImageKeyConverter))]
        public string SelectedImageKey { get; set; }

        /// <summary>
        /// 获取或设置用于指示的状态的图像的键 System.Windows.Forms.TreeNode 时父 System.Windows.Forms.TreeView
        /// 具有其 System.Windows.Forms.TreeView.CheckBoxes 属性设置为 false。
        /// </summary>
        /// <returns>用于指示的状态的图像的键 System.Windows.Forms.TreeNode。</returns>
        [DefaultValue("")]
        [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [RelatedImageList("TreeView.StateImageList")]
        [Category("行为")]
        [Description("标识在节点上以指示其当前状态的图像。")]
        [TypeConverter(typeof(ImageKeyConverter))]
        public string StateImageKey { get; set; }

        /// <summary>
        /// 获取或设置用于指示的状态的图像的索引 System.Windows.Forms.TreeNode 时父 System.Windows.Forms.TreeView
        /// 具有其 System.Windows.Forms.TreeView.CheckBoxes 属性设置为 false。
        /// </summary>
        /// <returns>用于指示的状态的图像的索引 System.Windows.Forms.TreeNode。</returns>
        [DefaultValue(-1)]
        [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [RelatedImageList("TreeView.StateImageList")]
        [Category("行为")]
        [Description("在TreeVview上的CheckBox设置为 false 时显示的StatelmageList中的索引。")]
        //[TypeConverter(typeof(NoneExcludedImageIndexConverter))]
        public int StateImageIndex { get; set; }

        /// <summary>
        /// 获取或设置包含有关树中节点的数据的对象。
        /// </summary>
        /// <returns>System.Object ，其中包含有关树中节点的数据。 默认值为 null。</returns>
        [Bindable(true)]
        [DefaultValue(null)]
        [Localizable(false)]
        [Category("数据")]
        [Description("与对象关联的用户定义数据。")]
        [TypeConverter(typeof(StringConverter))]
        public object Tag { get; set; }

        /// <summary>
        /// 获取或设置树节点的标签中显示的文本。
        /// </summary>
        /// <returns>显示的树节点标签中的文本。</returns>
        [Localizable(true)]
        [Category("外观")]
        [Description("树节点的标签中显示的文字。")]
        public string Text { get; set; }

        /// <summary>
        /// 获取或设置当鼠标指针悬停时显示的文本 System.Windows.Forms.TreeNode。
        /// </summary>
        /// <returns>获取当鼠标指针悬停时显示的文本 System.Windows.Forms.TreeNode。</returns>
        [DefaultValue("")]
        [Localizable(false)]
        [Category("外观")]
        [Description("当鼠标悬停在节点上时显示的ToolTip文本。")]
        public string ToolTipText { get; set; }

        /// <summary>
        /// 获取的集合 System.Windows.Forms.TreeNode 分配给当前树节点对象。
        /// </summary>
        /// <returns>一个 System.Windows.Forms.TreeNodeCollection ，表示分配给当前树节点的树节点。</returns>
        [Browsable(false)]
        [ListBindable(false)]
        public TreeNodeCollection Nodes
        {
            get
            {
                if (nodes is null)
                {
                    nodes = new TreeNodeCollection();
                    nodes.parent = this;
                    nodes.treeView = this.TreeView;
                }
                return nodes;
            }
        }

        /// <summary>
        /// 获取或设置树节点处于选定状态时显示的图像的图像列表索引值。
        /// </summary>
        /// <returns>一个表示在分配的图像位置的从零开始的索引值 System.Windows.Forms.ImageList。</returns>
        [DefaultValue(-1)]
        [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        [RefreshProperties(RefreshProperties.Repaint)]
        [RelatedImageList("TreeView.ImageList")]
        [Category("行为")]
        [Description("当树节点处于未选中状态时显示的图像的 ImageList 索引值。")]
        [TypeConverter(typeof(TreeViewImageIndexConverter))]
        public int ImageIndex { get; set; }

        /// <summary>
        /// 获取或设置树节点的前景色。
        /// </summary>
        /// <returns>前台 System.Drawing.Color 节点的树节点。</returns>
        [Category("外观")]
        [Description("树节点的前景色。")]
        public Color ForeColor { get; set; }

        /// <summary>
        /// 获取当前的树节点从根树节点的路径。
        /// </summary>
        /// <returns>从根树节点到当前的树节点的路径。</returns>
        /// <exception cref="T:System.InvalidOperationException:">此节点不包含在 System.Windows.Forms.TreeView。</exception>
        [Browsable(false)]
        public string FullPath
        {
            get
            {
                if (this.TreeView is null)
                    return string.Empty;
                StringBuilder builder = new StringBuilder();
                TreeNode node = this;
                do
                {
                    builder.Insert(0, this.TreeView.PathSeparator + node.Name);
                    node = node.Parent;
                } while (node is not null);
                return builder.ToString();
            }
        }

        /// <summary>
        /// 获取或设置树节点的背景色。
        /// </summary>
        /// <returns>后台 System.Drawing.Color 节点的树节点。 默认值为 System.Drawing.Color.Empty。</returns>
        [Category("外观")]
        [Description("树节点的背景色。")]
        public Color BackColor { get; set; }

        /// <summary>
        /// 获取树节点的边界。
        /// </summary>
        /// <returns>System.Drawing.Rectangle 表示树节点的边界。</returns>
        [Browsable(false)]
        public Rectangle Bounds => bounds;
        /// <summary>
        /// 获取或设置一个值，指示树节点是否处于选中状态。
        /// </summary>
        /// <returns>true 如果树节点处于选中状态，则否则为 false。</returns>
        [DefaultValue(false)]
        [Category("行为")]
        [Description("指示树节点是否处于选中状态。")]
        public bool Checked
        {
            get => @checked;
            set
            {
                @checked = value;
                this.TreeView?.Invalidate();
            }
        }

        /// <summary>
        /// 获取父树节点分配给树视图。
        /// </summary>
        /// <returns>一个 System.Windows.Forms.TreeView 表示树节点分配到的父树视图或 null 如果该节点尚未分配给树视图。</returns>
        [Browsable(false)]
        public TreeView TreeView
        {
            get => this.parentCollection?.treeView;
        }

        /// <summary>
        /// 获取或设置与此树节点关联的快捷菜单。
        /// </summary>
        /// <returns>System.Windows.Forms.ContextMenuStrip 与树节点关联。</returns>
        [DefaultValue(null)]
        [Category("行为")]
        [Description("当用户右击该控件时显示的快捷菜单。")]
        public virtual ContextMenuStrip ContextMenuStrip { get; set; }

        /// <summary>
        /// 获取树节点集合中的第一个子树节点。
        /// </summary>
        /// <returns>第一个子级 System.Windows.Forms.TreeNode 中 System.Windows.Forms.TreeNode.Nodes 集合。</returns>
        [Browsable(false)]
        public TreeNode FirstNode
        {
            get
            {
                if (this.Nodes.Count > 0)
                    return this.Nodes[0];
                else
                    return null;
            }
        }

        /// <summary>
        /// 获取或设置树节点的名称。
        /// </summary>
        /// <returns>一个 System.String ，它表示树节点的名称。</returns>
        [Category("外观")]
        [Description("对象的名称。")]
        public string Name { get; set; }

        /// <summary>
        /// 获取与此树节点关联的快捷菜单。
        /// </summary>
        /// <returns>System.Windows.Forms.ContextMenu 树节点与该键相关联。</returns>
        [DefaultValue(null)]
        [Category("行为")]
        [Description("当用户右击该控件时显示的快捷菜单。")]
        public virtual ContextMenu ContextMenu { get; set; }

        ///// <summary>
        ///// 将复制的树节点和此树中节点处打开的整个子树。
        ///// </summary>
        ///// <returns>System.Object ，表示克隆 System.Windows.Forms.TreeNode。</returns>
        //public virtual object Clone()
        //{
        //}

        /// <summary>
        /// 折叠 System.Windows.Forms.TreeNode 并可选择折叠其子级。
        /// </summary>
        /// <param name="ignoreChildren">true 将子节点保留在其当前状态; false 可折叠子节点。</param>
        public void Collapse(bool ignoreChildren)
        {
            this.isExpanded = false;
            if (!ignoreChildren)
            {
                TreeNodeCollection nodeCollection = this.Nodes;
                Collapse(nodeCollection);
            }

            void Collapse(TreeNodeCollection nodeCollection)
            {
                foreach (TreeNode node in nodeCollection)
                {
                    node.isExpanded = false;
                    if (node.Nodes.Count > 0)
                        Collapse(node.Nodes);
                }
            }
            this.TreeView.Invalidate();
        }

        /// <summary>
        /// 折叠树节点。
        /// </summary>
        public void Collapse()
        {
            this.isExpanded = false;
            this.TreeView.Invalidate();
        }

        ///// <summary>
        ///// 确保可见，请展开树节点和滚动树视图控件，根据需要树节点。
        ///// </summary>
        //public void EnsureVisible();

        /// <summary>
        /// 展开树节点。
        /// </summary>
        public void Expand()
        {
            this.isExpanded = true;
            this.TreeView?.Invalidate();
        }

        /// <summary>
        /// 展开所有子树节点。
        /// </summary>
        public void ExpandAll()
        {
            this.isExpanded = true;
            ExpandAll(this.Nodes);

            void ExpandAll(TreeNodeCollection nodeCollection)
            {
                foreach (TreeNode node in nodeCollection)
                {
                    node.isExpanded = true;
                    if (node.Nodes.Count > 0)
                        ExpandAll(node.Nodes);
                }
            }
            this.TreeView?.Invalidate();
        }

        ///// <summary>
        ///// 返回子树节点的数。
        ///// </summary>
        ///// <param name="includeSubTrees">true 如果在生成的计数包括在此树节点; 间接根的所有树节点否则为 false。</param>
        ///// <returns>分配给子树节点数 System.Windows.Forms.TreeNode.Nodes 集合。</returns>
        //public int GetNodeCount(bool includeSubTrees)
        //{
        //    return this.Nodes.Count;
        //}

        /// <summary>
        /// 从树视图控件中移除当前树节点。
        /// </summary>
        public void Remove()
        {
            this.parentCollection.Remove(this);
        }

        /// <summary>
        /// 切换到任何一个的树节点展开或折叠状态。
        /// </summary>
        public void Toggle()
        {
            this.isExpanded = !this.isExpanded;
            this.TreeView.Invalidate();
        }
    }
}
